
#include "BfcpMessage.hxx"
#include "bfcp_message_processing/bfcp_strings.h"

using namespace resip;

namespace bfcp
{
    BfcpMessage::BfcpMessage(int primitive, unsigned int cid, unsigned short uid, unsigned short tid, bool is_request/* = true */)
        : mRequest(is_request), mResponse(!is_request), mRawMsg(NULL), mParsedMsg(NULL), mArgs(NULL)
    {
        mArgs = bfcp_new_arguments();
        mArgs->entity = bfcp_new_entity(cid, tid, uid);
        mArgs->primitive = primitive;
    }

    BfcpMessage::BfcpMessage(unsigned char* buffer, unsigned short int length, const BfcpNetTuple& source, const BfcpNetTuple& receivedTransport)
        : mRequest(false), mResponse(false), mRawMsg(NULL), mParsedMsg(NULL), mArgs(NULL)
    {
        mRawMsg = bfcp_new_message(buffer, length);
        if (parseRawMsg())
        {
            mReceivedTransportTuple = receivedTransport;
            mSource = source;
        }
        else
        {
            mParsedMsg = NULL;
            freeMem();
        }
    }
    
    BfcpMessage::~BfcpMessage()
    {
        freeMem();
    }

    const bfcp_received_message_error* BfcpMessage::getErrors() const
    {
        return mParsedMsg ? mParsedMsg->errors : NULL;
    }

    UInt16 BfcpMessage::getTransactionId() const
    {
        if (isIncoming())
        {
            return mParsedMsg->entity->transactionID;;
        }
        else
        {
            return mArgs->entity->transactionID;
        }
    }

    UInt32 BfcpMessage::getConferenceId() const
    {
        if (isIncoming())
        {
            return mParsedMsg->entity->conferenceID;
        }
        else
        {
            return mArgs->entity->conferenceID;
        }
    }

    UInt16 BfcpMessage::getUserId() const
    {
        if (isIncoming())
        {
            return mParsedMsg->entity->userID;
        }
        else
        {
            return mArgs->entity->userID;
        }
    }

    UInt16 BfcpMessage::getPrimitive() const
    {
        if (isIncoming())
        {
            return mParsedMsg->primitive;
        }
        else
        {
            return mArgs->primitive;
        }
    }

    UInt16 BfcpMessage::getFloorStatusStatus() const
    {
        if (getPrimitive() == FloorStatus)
        {
            return mArgs->frqInfo->oRS->rs->rs;
        }
        else
        {
            return 0;
        }
    }

    bool BfcpMessage::isClientTransaction() const
    {
        return getTransactionId() != 0;
    }

    bool BfcpMessage::isFromWire() const
    {
        return mReceivedTransportTuple.getType() != UNKNOWN_TRANSPORT;
    }

    bool BfcpMessage::hasError() const
    {
        return mParsedMsg ? (mParsedMsg->errors ? true : false) : true;
    }

    void BfcpMessage::flush()
    {
        if (!mRawMsg)
        {
            mRawMsg = bfcp_build_message(mArgs);
        }
    }

    bfcp_message* BfcpMessage::copyRawData() const
    {
        return mRawMsg ? bfcp_new_message(mRawMsg->buffer, mRawMsg->length) : NULL;
    }

    EncodeStream& BfcpMessage::encode(EncodeStream& strm) const
    {
        return strm;
    }

    EncodeStream& BfcpMessage::encodeBrief(EncodeStream& strm) const
    {
        UInt16 primitive = getPrimitive();
        if (primitive < FloorRequest || primitive > GoodbyeAck)
        {
            strm << "Unknown (" << primitive << ")" << std::endl;
        }
        else
        {
            strm << bfcp_primitive[primitive - 1].description << " (" << primitive << ")" << std::endl;
        }
        strm << "Transaction ID: " << getTransactionId() << std::endl;
        strm << "Conference ID: " << getConferenceId() << std::endl;
        strm << "User ID:" << getUserId() << std::endl;

        return strm;
    }


    bool BfcpMessage::parseRawMsg()
    {
        try
        {
            mParsedMsg = bfcp_parse_message(mRawMsg);
        }
        catch (...)
        {
            return false;
        }

        return mParsedMsg ? true : false;
    }

    void BfcpMessage::freeMem()
    {
        bfcp_free_arguments(mArgs);
        bfcp_free_received_message(mParsedMsg);
        bfcp_free_message(mRawMsg);
    }


}// namespace bfcp
